package main

import (
	"bytes"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"

	"github.com/dustin/go-humanize"
	// "github.com/fsnotify/fsnotify"
	"github.com/go-resty/resty/v2"
	gonanoid "github.com/matoous/go-nanoid/v2"
	"github.com/shirou/gopsutil/disk"
	"github.com/spf13/viper"
)

const (
	configFileName                = "config"
	configFileType                = "toml"
	configFilePath                = "config"
	configFileKeyWebhookUrl       = "webhook-url"
	configFileKeyTimeFormatLayout = "time-format-layout"
	configFileKeyTemplateFile     = "template-file"
)

func main() {

	fmt.Println("================================================================")
	// watcher, err := fsnotify.NewWatcher()
	// if err != nil {
	// 	log.Fatal("NewWatcher failed: ", err)
	// }
	postData := generatePostData()
	// var str bytes.Buffer
	// _ = json.Indent(&str, []byte(postData), "", "    ")
	// log.Println(str.String())
	log.Println(postData)
	fmt.Println("================================================================")
	// 发送
	transmit(postData)
}

func init() {
	viper.SetConfigName(configFileName)
	viper.SetConfigType(configFileType)
	viper.AddConfigPath(configFilePath)

	viper.SetDefault(configFileKeyTimeFormatLayout, time.RFC3339)

	err := viper.ReadInConfig()
	if err != nil {
		log.Panic(err)
	}

}

func getCurrentFormatTime() string {
	curTime := time.Now()

	if !viper.IsSet(configFileKeyTimeFormatLayout) {
		// 没有这个key
		log.Panicf("Don't have key:%v", configFileKeyTimeFormatLayout)
	}
	timeFormatLayout := viper.GetString(configFileKeyTimeFormatLayout)
	return curTime.Format(timeFormatLayout)
}

func process(t *template.Template, vars any) string {
	var tmplBytes bytes.Buffer
	err := t.Execute(&tmplBytes, vars)
	if err != nil {
		log.Panic(err)
	}
	return tmplBytes.String()
}

func processFile(templateFile string, vars any) string {
	tmpl, err := template.ParseFiles(templateFile)
	if err != nil {
		log.Panic(err)
	}
	return process(tmpl, vars)
}

// 摘自humanize库 ftoa.go
func stripTrailingZeros(s string) string {
	offset := len(s) - 1
	for offset > 0 {
		if s[offset] == '.' {
			offset--
			break
		}
		if s[offset] != '0' {
			break
		}
		offset--
	}
	return s[:offset+1]
}

func getDiskUsageInfo() (size string, used string, avail string, usePercent string) {
	parts, err := disk.Partitions(false)
	if err != nil {
		log.Panic(err)
	}
	for _, mountpoint := range parts {
		if mountpoint.Mountpoint == "/data" {
			log.Printf("mountpoint=%v\n", mountpoint.Mountpoint)
			usageStat, err := disk.Usage(mountpoint.Mountpoint)
			if err != nil {
				log.Panic(err)
			}
			size = humanize.Bytes(usageStat.Total)
			used = humanize.Bytes(usageStat.Free)
			avail = humanize.Bytes(usageStat.Used)
			usePercent = stripTrailingZeros(strconv.FormatFloat(usageStat.UsedPercent, 'f', 1, 64)) + "%"

			//找到就退出
			break
		}
	}

	return
}

func getNanoId() string {
	id, err := gonanoid.New()
	if err != nil {
		panic(err)
	}
	return id
}

func generatePostData() string {
	if !viper.IsSet(configFileKeyTemplateFile) {
		// 没有这个key
		log.Panicf("Don't have key:%v", configFileKeyTemplateFile)
	}
	templateFile := viper.GetString(configFileKeyTemplateFile)
	log.Printf("templateFile=%v", templateFile)
	vars := make(map[string]any)
	vars["alert_time"] = template.HTML(getCurrentFormatTime())
	vars["hostname"], _ = os.Hostname()
	vars["size"], vars["used"], vars["avail"], vars["usePercent"] = getDiskUsageInfo()
	vars["nanoid"] = getNanoId()
	return processFile(templateFile, vars)

}

func transmit(postData string) {
	if !viper.IsSet(configFileKeyWebhookUrl) {
		// 没有这个key
		log.Panicf("Don't have key:%v", configFileKeyWebhookUrl)
	}
	webHookUrl := viper.GetString(configFileKeyWebhookUrl)
	// Create a Resty Client
	client := resty.New()

	resp, err := client.R().
		SetHeader("Content-Type", "application/json").
		SetContentLength(true).
		SetBody(postData).
		Post(webHookUrl)

	// Explore response object
	fmt.Println("Response Info:")
	fmt.Println("  Error      :", err)
	fmt.Println("  Status Code:", resp.StatusCode())
	fmt.Println("  Status     :", resp.Status())
	fmt.Println("  Proto      :", resp.Proto())
	fmt.Println("  Time       :", resp.Time())
	fmt.Println("  Received At:", resp.ReceivedAt())
	fmt.Println("  Body       :\n", resp)
	fmt.Println("================================================================")
	fmt.Println("Headers:")
	for key, value := range resp.Header() {
		fmt.Println(key, "=", value)
	}
	fmt.Println(http.StatusOK)

}
